package http_util

import (
	"bytes"
	"github.com/pkg/errors"
	"io"
	"net/http"
	"strings"
	"time"
	"trpg-common/logger"
	"trpg-common/utils/json_util"
)

func GetWithOutHeader(url string, args map[string]string) map[string]interface{} {
	url += "?"
	for key, value := range args {
		url += key + "=" + value + "&"
	}
	resp, err := http.Get(url)
	if err != nil && resp.StatusCode == 200 {
		logger.Logger.Panicf("%+v", errors.Wrap(err, "error in get "+url))
	}
	return readResult(resp)
}

func GetWithHeader(url string, args map[string]string, header map[string]string) map[string]interface{} {
	url += "?"
	for key, value := range args {
		url += key + "=" + value + "&"
	}
	request, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		logger.Logger.Panicf("%+v", errors.Wrap(err, "error in get "+url))
	}
	for key, value := range header {
		request.Header.Set(key, value)
	}
	response, err := http.DefaultClient.Do(request)
	if err != nil {
		logger.Logger.Panicf("%+v", errors.Wrap(err, "error in get "+url))
	}
	return readResult(response)
}

func PostWithOutHeader(url string, contentType string, requestBody string) map[string]interface{} {
	resp, err := http.Post(url, contentType, strings.NewReader(requestBody))
	if err != nil {
		logger.Logger.Panicf("%+v", errors.Wrap(err, "error in post "+url))
	}
	return readResult(resp)
}

func PostWithHeader(url string, contentType string, requestBody string, header map[string]string) map[string]interface{} {
	request, err := http.NewRequest(http.MethodPost, url, strings.NewReader(requestBody))
	if err != nil {
		logger.Logger.Panicf("%+v", errors.Wrap(err, "error in get "+url))
	}
	request.Header.Set("Content-Type", contentType)
	for key, value := range header {
		request.Header.Set(key, value)
	}
	response, err := http.DefaultClient.Do(request)
	if err != nil {
		logger.Logger.Panicf("%+v", errors.Wrap(err, "error in get "+url))
	}
	return readResult(response)
}

func Request(method string, url string, header map[string]string, cookie map[string]string, requestBodyReader *bytes.Buffer, timeoutMilli int64, openRedirect bool) (*http.Response, error) {
	request, err := http.NewRequest(method, url, requestBodyReader)
	if err != nil {
		return nil, err
	}
	for k, v := range header {
		request.Header.Set(k, v)
	}
	for k, v := range cookie {
		request.AddCookie(&http.Cookie{
			Name:  k,
			Value: v,
		})
	}
	client := http.Client{
		Timeout: time.Duration(int64(time.Millisecond) * timeoutMilli),
	}
	if openRedirect {
		// 限制重定向5次
		client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
			if len(via) > 5 {
				return errors.New("redirect too times")
			}
			return nil
		}
	} else {
		// 禁止重定向
		client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
			return http.ErrUseLastResponse
		}
	}
	response, err := client.Do(request)
	return response, err
}

func readResult(resp *http.Response) map[string]interface{} {
	var buffer [512]byte
	result := bytes.NewBuffer(nil)
	for {
		n, err := resp.Body.Read(buffer[0:])
		result.Write(buffer[0:n])
		if err != nil && err == io.EOF {
			break
		} else if err != nil {
			logger.Logger.Panicf("%+v", errors.Wrap(err, "error in reading response body"))
		}
	}
	m := make(map[string]interface{})
	json_util.UnMarshal(result.Bytes(), &m)
	defer resp.Body.Close()
	return m
}
